home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dskut / p22v12.zip / PATCH22.C < prev    next >
C/C++ Source or Header  |  1991-08-08  |  24KB  |  570 lines

  1. #include <conio.h>
  2. #include <dos.h>
  3. #include <ctype.h>
  4. #undef tolower             /* use function version instead of macro version */
  5. #undef toupper
  6. #include <stdarg.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. /*------------------------- PATCH22 ---------------------------------------
  12.  * just compile as: cl patch22.c
  13.  *
  14.  * exit value (byte):
  15.  *   -5: error in patch command string
  16.  *   -4: file with patch commands not found
  17.  *   -3: file to be patched not found
  18.  *   -2: error in patch commandline (if not silent help is displayed)
  19.  *   -1: not used (reserved for calling through spawn functions)
  20.  * >= 0: total no of patches made
  21.  *-------------------------------------------------------------------------*/
  22.  
  23. /*----------------------------- Revision history ---------------------------
  24.  *  8-08-91: Released version 1.2
  25.  * 22-07-91: - The date/time stamp of a file is reset if any patches are made.
  26.  *           - Added (simple) password protection option.
  27.  *  7-07-91: - If user chooces Quit, now breaks out of while loop, instead
  28.  *           of spooling to end of file.
  29.  *           - Corrected bug pointed out by Ernst Raedecker of Amsterdam:
  30.  *           find function did not allow for search string matching within
  31.  *           itself. (See patch22.doc)
  32.  *           - Now the next search continues one byte after the start of the
  33.  *           previous match.
  34.  * 12-05-91: cctos() converts character following \ to lowercase, changed
  35.  *           ffindi() slightly.
  36.  * 11-05-91: Now checks for progress in conditions field (+A000 led to
  37.  *           infinite loop). Added case insensitive option.
  38.  * 11-04-91: Added <Q>uit option to verbose patching.
  39.  *  5-04-91: Replaced function Abort by message (using stdarg).
  40.  *           Now continues with next patch if taking patches from file and
  41.  *           file to be patched not found.
  42.  * 28-02-91: Fixed bug in ffindf function (the first non-matching char after
  43.  *           a match was not used as the starting char in the next search).
  44.  * 22-02-91: Added error message if 0 patches requested.
  45.  * 18-02-91: Command line patch didn't work, bug fixed.
  46.  * 03-02-91: Added \w char escape codes, replaced mallocs by static arrays,
  47.  *           using scanf to read \x##, \w####, \### (see NB.2 in cctos).
  48.  * 02-02-91: Less silent; removed error in scanning upto ?; added missing
  49.  *           breaks in switching for \ char escape codes.
  50.  *--------------------------------------------------------------------------*/
  51.  
  52.  
  53. /*=========================== global help ==================================*/
  54. #define ERR_EXIT  {  fprintf(stderr, sUsage, sProgram, sVersion, sAuthor, \
  55.     sProgram, sProgram, sProgram, sProgram);  exit(0); }
  56.  
  57. char *sProgram = "PATCH22";
  58. char *sVersion = "version 1.2";
  59. char *sAuthor = "(C) J.A. Doornik,  8 August 1991.";
  60.  
  61. char  sP22[] = { '«','p','2','2','_','»' };                    /* signature */
  62. char  sPassword[] = "\0 gf ggv aewf bvsbago";      /* password: 21 chars+\0 */
  63.                 /* leading \0 indicates no password; avoid .exe compression */
  64.  
  65. char *sUsage =
  66.     "\n%s %s: patches any file %s\n"
  67.     "\nUsage:\t%s fname  +##*##si\?search_text\?new_text\?"
  68.     "\n   or:\t%s @fname\n"
  69.     "\nfname\tfile to be patched"
  70.     "\n+##\t+ve or -ve offset from the start of the search text"
  71.     "\n*##\tmaximum number of patches"
  72.     "\ns\tsilent patch, default is confirm each patch"
  73.     "\ni\tcase insensitive patch, default is case sensitive"
  74.     "\n@fname\tfile with (multiple) %s commands, with format:"
  75.     "\n\tfname  +##*##s\?search_text\?new_text\?"
  76.     "\ntext\tC-type character constant, possibly including:"
  77.     "\n\t\\a (07h), \\b (08h), \\f (0Ch), \\n (0Ah), \\r (0Dh), \\t (09h), \\v (0Bh);"
  78.     "\n\t\\###   (octal byte, not more than 3 digits);"
  79.     "\n\t\\w#### (hexadecimal word, not more than 4 digits);"
  80.     "\n\t\\x##   (hexadecimal byte, not more than 2 digits);"
  81.     "\n\t\\h     (the rest of the text contains two-digit hexadecimal bytes)."
  82.     "\n\tThe characters \\ \? \' \" must be written as: \\\" \\\\ \\\? \\\' \\\"."
  83.     "\n\nEg.\t%s test *1\?\h0d0a00\?\\r\\n\\0\?"
  84.     "\nwhich makes one change, where the replace text equals the search text.\n";
  85.  
  86.  
  87. /*=========================== global types =================================*/
  88. typedef unsigned char   byte;       /* b   */
  89. typedef unsigned short  bool;       /* f   */
  90. typedef unsigned short  word;       /* w   */
  91.  
  92. #define  FALSE  0
  93. #define  TRUE   !FALSE
  94.  
  95. struct Patch22                         /* structure to store all patch info */
  96. {
  97.     byte *sSearch, *sNew;                       /* search text and new text */
  98.     int  cNew, cSearch;           /* # of bytes in search text and new text */
  99.     int  iMaxpatch, cPatch;         /* maximum and actual number of patches */
  100.     int  iMaxfind;                               /* maximum number of finds */
  101.     long lOffset;                     /* offset from start of search string */
  102. };
  103.  
  104. /*=========================== global data ==================================*/
  105. #define MAXPATLEN 1024                    /* maximum length of a patch text */
  106. static bool  fVerbose_ = TRUE;
  107. static int   iColor_hi = 0x001f, iColor_lo = 0x0017;
  108. static char *s16dots =  "∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙";
  109. static char *s16dots3 = "∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ";
  110.  
  111. int  ffindfn(FILE *f, byte *s, int slen);                     /* prototypes */
  112. int  ffindfi(FILE *f, byte *s, int slen);
  113. int  (* ffindf)(FILE *, byte *, int) = ffindfn;      /* case sensitive find */
  114.  
  115. /* --------------- files and  internal buffer for in/output --------------- */
  116. #define BUFLEN 20480                                          /* 20K buffer */
  117. static byte  inbuf_[BUFLEN];
  118. static FILE  *infile_, *comfile_;             /* files are global variables */
  119. unsigned uFdate, uFtime;             /* date and time of file to be patched */
  120.  
  121. /*--------------------------- procedure message ----------------------------*/
  122. void message(int exitcode, char *msg, ...)
  123. {
  124.     va_list args;
  125.  
  126.     fprintf(stderr, "%s error: ", sProgram);
  127.     va_start(args, msg);    vfprintf(stderr, msg, args);    va_end(args);
  128.     fprintf(stderr, ".\n");
  129.  
  130.     if (exitcode != 0)  exit(exitcode);
  131. }
  132. /*--------------------------- end procedure message ------------------------*/
  133.  
  134.  
  135. /*------------------ open_infile/close_infile/open_comfile -----------------*/
  136. int  open_infile(char *infname)                   /* get file to be patched */
  137. {
  138.     if ( (infile_ = fopen(infname, "r+b")) == NULL) /* read & write, binary */
  139.     {   message(0, "cannot open file %s", infname);
  140.         return(FALSE);
  141.     }
  142.     _dos_getftime(fileno(infile_), &uFdate, &uFtime); /* get file date/time */
  143.     setvbuf(infile_, inbuf_, _IOFBF, BUFLEN);
  144. return(TRUE);
  145. }
  146.  
  147. void close_infile(int npatches)                       /* close patched file */
  148. {
  149.     if (npatches > 0)
  150.         _dos_setftime(fileno(infile_), uFdate, uFtime);  /* reset file date */
  151.     fclose(infile_);
  152. }
  153.  
  154. int  open_comfile(char *comfname)           /* get file with patch commands */
  155. {
  156.     if ( (comfile_ = fopen(comfname, "r")) == NULL)                 /* read */
  157.     {   message(0, "cannot open file %s", comfname);
  158.         return(FALSE);
  159.     }
  160. return(TRUE);
  161. }
  162. /*------------------ END open_infile/close_infile/open_comfile -------------*/
  163.  
  164.  
  165. /*------------------------------- getpatch ---------------------------------*/
  166. int   getpatch(FILE *f, char *infname, byte *s)
  167. {                   /* gets fname +##*##s?search_text?new_text? from a file */
  168.     int  ch, len;
  169.  
  170.     do
  171.     {   fscanf(f, " ");                                 /* skip white space */
  172.         ch = 0;  fscanf(f, ";%n", &ch);            /* check if there is a ; */
  173.         if (ch > 0)  fscanf(f, "%*[^\n]");    /* skip comment lines upto \n */
  174.     } while (!feof(f) && ch > 0);
  175.     if (fscanf(f, " %s ", infname) != 1)  return(EOF);
  176.  
  177.     len = MAXPATLEN - 1;                      /* read upto first question mark */
  178.     while (--len > 0 && (ch = fgetc(f)) != EOF && ch != '\?')
  179.         if (ch != '\n') *s++ = ch;
  180.     *s++ = '\?';
  181.